#! /bin/sh /usr/share/dpatch/dpatch-run
## 80_6719_channel_thread_p2.dpatch by  <root@mythserver.home.rodriguez-vudoyra.com>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: No description.

@DPATCH@
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/signalmonitor.h mythtv-0.22.0-fixes23003/libs/libmythtv/signalmonitor.h
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/signalmonitor.h	2009-10-14 20:32:51.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/signalmonitor.h	2009-12-27 02:07:16.000000000 -0600
@@ -27,6 +27,8 @@
 
 inline QString sm_flags_to_string(uint64_t);
 
+class TVRec;
+
 class SignalMonitor
 {
   public:
@@ -40,7 +42,7 @@
     // // // // // // // // // // // // // // // // // // // // // // // //
     // Control  // // // // // // // // // // // // // // // // // // // //
 
-    virtual void Start();
+    virtual void Start(bool waitfor_tune);
     virtual void Stop();
     virtual void Kick();
     virtual bool WaitForLock(int timeout = -1);
@@ -84,6 +86,13 @@
      */
     void SetNotifyFrontend(bool notify) { notify_frontend = notify; }
 
+    /** \brief Indicate if table monitoring is needed
+     *  \param monitor if true parent->SetupDTVSignalMonitor is called
+     *         after the channel is tuned.
+     */
+    void SetMonitoring(TVRec * parent, bool EITscan, bool monitor)
+        { pParent = parent; eit_scan = EITscan, tablemon = monitor; }
+
     /** \brief Sets the number of milliseconds between signal monitoring
      *         attempts in the signal monitoring thread.
      *
@@ -97,6 +106,7 @@
     // Listeners   // // // // // // // // // // // // // // // // // // //
     void AddListener(SignalMonitorListener *listener);
     void RemoveListener(SignalMonitorListener *listener);
+
     void SendMessage(SignalMonitorMessageType type,
                      const SignalMonitorValue &val);
     void SendMessageAllGood(void);
@@ -109,6 +119,8 @@
     static void* SpawnMonitorLoop(void*);
     virtual void MonitorLoop();
 
+    bool IsChannelTuned(void);
+
     /// \brief This should be overridden to actually do signal monitoring.
     virtual void UpdateValues() { ; }
 
@@ -140,6 +152,8 @@
     /// We've seen something indicating whether the data stream is encrypted
     static const uint64_t kDTVSigMon_CryptSeen  = 0x0000000200ULL;
 
+    static const uint64_t kSigMon_Tuned         = 0x0000000400ULL;
+
     /// We've seen a PAT matching our requirements
     static const uint64_t kDTVSigMon_PATMatch   = 0x0000001000ULL;
     /// We've seen a PMT matching our requirements
@@ -185,6 +199,7 @@
   protected:
     pthread_t    monitor_thread;
     ChannelBase *channel;
+    TVRec       *pParent;
     int          capturecardnum;
     uint64_t     flags;
     int          update_rate;
@@ -193,10 +208,14 @@
     bool         exit;
     bool         update_done;
     bool         notify_frontend;
+    bool         is_tuned;
+    bool         tablemon;
+    bool         eit_scan;
     QString      error;
 
     SignalMonitorValue signalLock;
     SignalMonitorValue signalStrength;
+    SignalMonitorValue channelTuned;
 
     vector<SignalMonitorListener*> listeners;
 
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/signalmonitorlistener.h mythtv-0.22.0-fixes23003/libs/libmythtv/signalmonitorlistener.h
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/signalmonitorlistener.h	2009-10-14 20:32:50.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/signalmonitorlistener.h	2009-12-27 02:08:12.000000000 -0600
@@ -9,6 +9,7 @@
 
 typedef enum {
     kAllGood,
+    kStatusChannelTuned,
     kStatusSignalLock,
     kStatusSignalStrength,
     kStatusSignalToNoise,
@@ -30,6 +31,13 @@
      */
     virtual void AllGood(void) = 0;
 
+    /** \brief Singal to be sent with change change status.
+     *
+     *   Note: Signals are only sent once the monitoring thread
+     *         has been started.
+     */
+    virtual void StatusChannelTuned(const SignalMonitorValue&) = 0;
+
     /** \brief Signal to be sent as true when it is safe to begin
      *   or continue recording, and false if it may not be safe.
      *
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/tv_play.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/tv_play.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/tv_play.cpp	2009-12-27 02:00:21.000000000 -0600
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/tv_play.cpp	2009-12-27 02:11:14.000000000 -0600
@@ -7278,6 +7278,7 @@
     float snr  = 0.0f;
     uint  ber  = 0xffffffff;
     int   pos  = -1;
+    int   tuned = -1;
     QString pat(""), pmt(""), mgt(""), vct(""), nit(""), sdt(""), crypt("");
     QString err = QString::null, msg = QString::null;
     for (it = slist.begin(); it != slist.end(); ++it)
@@ -7304,6 +7305,8 @@
             ber = it->GetValue();
         else if ("pos" == it->GetShortName())
             pos = it->GetValue();
+       else if ("tuned" == it->GetShortName())
+           tuned = it->GetValue();
         else if ("seen_pat" == it->GetShortName())
             pat = it->IsGood() ? "a" : "_";
         else if ("matching_pat" == it->GetShortName())
@@ -7337,6 +7340,7 @@
         infoMap["signal"] = QString::number(sig); // use normalized value
 
     bool    allGood = SignalMonitorValue::AllGood(slist);
+    char    tuneCode;
     QString slock   = ("1" == infoMap["slock"]) ? "L" : "l";
     QString lockMsg = (slock=="L") ? tr("Partial Lock") : tr("No Lock");
     QString sigMsg  = allGood ? tr("Lock") : lockMsg;
@@ -7349,9 +7353,18 @@
     if ((pos >= 0) && (pos < 100))
         sigDesc += " | " + tr("Rotor %1\%").arg(pos,2);
 
-    sigDesc = sigDesc + QString(" | (%1%2%3%4%5%6%7%8) %9")
-        .arg(slock).arg(pat).arg(pmt).arg(mgt).arg(vct)
-        .arg(nit).arg(sdt).arg(crypt).arg(sigMsg);
+    if (tuned == 1)
+        tuneCode = 't';
+    else if (tuned == 2)
+        tuneCode = 'F';
+    else if (tuned == 3)
+        tuneCode = 'T';
+    else
+        tuneCode = '_';
+
+    sigDesc = sigDesc + QString(" | (%1%2%3%4%5%6%7%8%9) %10")
+             .arg(tuneCode).arg(slock).arg(pat).arg(pmt).arg(mgt).arg(vct)
+             .arg(nit).arg(sdt).arg(crypt).arg(sigMsg);
 
     if (!err.isEmpty())
         sigDesc = err;
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/tv_rec.cpp mythtv-0.22.0-fixes23003/libs/libmythtv/tv_rec.cpp
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/tv_rec.cpp	2009-11-20 02:32:09.000000000 -0600
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/tv_rec.cpp	2009-12-27 02:33:23.000000000 -0600
@@ -379,6 +379,8 @@
                           bool hasLater)
 {
     QMutexLocker lock(&stateChangeLock);
+    QMutexLocker statelock(&stateChangeLock);
+    QMutexLocker pendlock(&pendingRecLock);
 
     if (secsleft < 0)
     {
@@ -416,10 +418,10 @@
 
     pendingRecordings[rcinfo->cardid].possibleConflicts = cardids;
 
-    stateChangeLock.unlock();
+    statelock.unlock();
     for (uint i = 0; i < cardids.size(); i++)
         RemoteRecordPending(cardids[i], rcinfo, secsleft, hasLater);
-    stateChangeLock.lock();
+    statelock.relock();
 }
 
 /** \fn TVRec::SetPseudoLiveTVRecording(ProgramInfo*)
@@ -451,6 +453,7 @@
  */
 void TVRec::CancelNextRecording(bool cancel)
 {
+    QMutexLocker pendlock(&pendingRecLock);
     VERBOSE(VB_RECORD, LOC + "CancelNextRecording("<<cancel<<") -- begin");
 
     PendingMap::iterator it = pendingRecordings.find(cardid);
@@ -536,7 +539,10 @@
     }
 
     PendingMap::iterator it = pendingRecordings.find(cardid);
+    PendingInfo pendinfo;
     bool cancelNext = false;
+    bool has_pending;
+
     if (it != pendingRecordings.end())
     {
         (*it).ask = (*it).doNotAsk = false;
@@ -549,15 +555,18 @@
     // Rescan pending recordings since the event loop may have deleted  
     // a stale entry.  If this happens the info pointer will not be valid 
     // since the HandlePendingRecordings loop will have deleted it. 
-    it = pendingRecordings.find(cardid); 
+    pendingRecLock.lock();
+    it = pendingRecordings.find(cardid);
+    pendinfo = *it;
+    has_pending = (it != pendingRecordings.end());
+    pendingRecLock.unlock();
 
     // If the needed input is in a shared input group, and we are
     // not canceling the recording anyway, check other recorders
-    if (!cancelNext &&
-        (it != pendingRecordings.end()) && (*it).possibleConflicts.size())
+    if (!cancelNext && has_pending && pendinfo.possibleConflicts.size())
     {
         VERBOSE(VB_RECORD, LOC + "Checking input group recorders - begin");
-        vector<uint> &cardids = (*it).possibleConflicts;
+        vector<uint> &cardids = pendinfo.possibleConflicts;
 
         uint mplexid = 0, sourceid = 0;
         vector<uint> cardids2;
@@ -580,8 +589,8 @@
 
             if (is_busy && !sourceid)
             {
-                mplexid  = (*it).info->GetMplexID();
-                sourceid = (*it).info->sourceid;
+                mplexid  = pendinfo.info->GetMplexID();
+                sourceid = pendinfo.info->sourceid;
             }
 
             if (is_busy &&
@@ -967,7 +976,6 @@
 void TVRec::ChangeState(TVState nextState)
 {
     QMutexLocker lock(&stateChangeLock);
-
     desiredNextState = nextState;
     changeState = true;
     WakeEventLoop();
@@ -1452,9 +1460,12 @@
             QDateTime now   = QDateTime::currentDateTime();
             bool has_finish = HasFlags(kFlagFinishRecording);
             bool has_rec    = pseudoLiveTVRecording;
+            bool enable_ui  = true;
+
+            pendingRecLock.lock();
             bool rec_soon   =
                 pendingRecordings.find(cardid) != pendingRecordings.end();
-            bool enable_ui  = true;
+            pendingRecLock.unlock();
 
             if (has_rec && (has_finish || (now > recordEndTime)))
             {
@@ -1625,6 +1636,8 @@
 
 void TVRec::HandlePendingRecordings(void)
 {
+    QMutexLocker pendlock(&pendingRecLock);
+
     if (pendingRecordings.empty())
         return;
 
@@ -1926,7 +1939,7 @@
  *   This method also grabs the ATSCStreamData() from the recorder
  *   if possible, or creates one if needed.
  */
-bool TVRec::SetupDTVSignalMonitor(void)
+bool TVRec::SetupDTVSignalMonitor(bool EITscan)
 {
     VERBOSE(VB_RECORD, LOC + "Setting up table monitoring.");
 
@@ -2060,6 +2073,12 @@
                      SignalMonitor::kDVBSigMon_WaitForPos);
         sm->SetRotorTarget(1.0f);
 
+        if (EITscan)
+        {
+            sm->GetStreamData()->SetVideoStreamsRequired(0);
+            sm->IgnoreEncrypted(true);
+        }
+
         VERBOSE(VB_RECORD, LOC + "Successfully set up MPEG table monitoring.");
         return true;
     }
@@ -2081,7 +2100,7 @@
  *  \param notify   If set we notify the frontend of the signal values
  *  \return true on success, false on failure
  */
-bool TVRec::SetupSignalMonitor(bool tablemon, bool notify)
+bool TVRec::SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
 {
     VERBOSE(VB_RECORD, LOC + "SetupSignalMonitor("
             <<tablemon<<", "<<notify<<")");
@@ -2097,27 +2116,22 @@
     // make sure statics are initialized
     SignalMonitorValue::Init();
 
-    if (SignalMonitor::IsSupported(genOpt.cardtype) && channel->Open())
-        signalMonitor = SignalMonitor::Init(genOpt.cardtype, cardid, channel);
+    if (channel->Open())
+        signalMonitor = SignalMonitor::Init(genOpt.cardtype, cardid,
+                                            channel);
 
     if (signalMonitor)
     {
         VERBOSE(VB_RECORD, LOC + "Signal monitor successfully created");
-        // If this is a monitor for Digital TV, initialize table monitors
-        if (GetDTVSignalMonitor() && tablemon && !SetupDTVSignalMonitor())
-        {
-            VERBOSE(VB_IMPORTANT, LOC_ERR +
-                    "Failed to setup digital signal monitoring");
-
-            return false;
-        }
 
+        signalMonitor->SetMonitoring(this, EITscan,
+                                     GetDTVSignalMonitor() && tablemon);
         signalMonitor->AddListener(this);
         signalMonitor->SetUpdateRate(kSignalMonitoringRate);
         signalMonitor->SetNotifyFrontend(notify);
 
         // Start the monitoring thread
-        signalMonitor->Start();
+        signalMonitor->Start(true);
     }
 
     return true;
@@ -2522,8 +2536,6 @@
  */
 bool TVRec::IsBusy(TunedInputInfo *busy_input, int time_buffer) const
 {
-    QMutexLocker lock(&stateChangeLock);
-
     TunedInputInfo dummy;
     if (!busy_input)
         busy_input = &dummy;
@@ -2545,6 +2557,7 @@
         chanid              = channel->GetChanID();
     }
 
+    QMutexLocker pendlock(&pendingRecLock);
     PendingMap::const_iterator it = pendingRecordings.find(cardid);
     if (!busy_input->inputid && (it != pendingRecordings.end()))
     {
@@ -3717,6 +3730,11 @@
 void TVRec::TuningFrequency(const TuningRequest &request)
 {
     DTVChannel *dtvchan = GetDTVChannel();
+
+    bool livetv = request.flags & kFlagLiveTV;
+    bool antadj = request.flags & kFlagAntennaAdjust;
+    bool has_dummy = false;
+
     if (dtvchan)
     {
         MPEGStreamData *mpeg = NULL;
@@ -3733,16 +3751,14 @@
 
         if (request.minorChan && (tuningmode == "atsc"))
         {
-            channel->SetChannelByString(request.channel);
-
+            channel->SelectChannel(request.channel);
             ATSCStreamData *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
             if (atsc)
                 atsc->SetDesiredChannel(request.majorChan, request.minorChan);
         }
         else if (request.progNum >= 0)
         {
-            channel->SetChannelByString(request.channel);
-
+            channel->SelectChannel(request.channel);
             if (mpeg)
                 mpeg->SetDesiredProgram(request.progNum);
         }
@@ -3771,9 +3787,11 @@
     if (channel && !channum.isEmpty())
     {
         if (!input.isEmpty())
-            ok = channel->SwitchToInput(input, channum);
+            channel->SelectInput(input, channum);
         else
-            ok = channel->SetChannelByString(channum);
+            channel->SelectChannel(channum);
+
+        ok = true;
     }
 
     if (!ok)
@@ -3800,13 +3818,7 @@
         }
     }
 
-    bool livetv = request.flags & kFlagLiveTV;
-    bool antadj = request.flags & kFlagAntennaAdjust;
-    bool use_sm = SignalMonitor::IsRequired(genOpt.cardtype);
-    bool use_dr = use_sm && (livetv || antadj);
-    bool has_dummy = false;
-
-    if (use_dr)
+    if (livetv || antadj)
     {
         // We need there to be a ringbuffer for these modes
         bool ok;
@@ -3832,60 +3844,51 @@
         has_dummy = true;
     }
 
-    // Start signal monitoring for devices capable of monitoring
-    if (use_sm)
+    // Start signal (or channel change) monitoring
+    VERBOSE(VB_RECORD, LOC + "Starting Signal Monitor");
+    bool error = false;
+    if (!SetupSignalMonitor(!antadj, request.flags & kFlagEITScan,
+                            livetv | antadj))
     {
-        VERBOSE(VB_RECORD, LOC + "Starting Signal Monitor");
-        bool error = false;
-        if (!SetupSignalMonitor(!antadj, livetv | antadj))
-        {
-            VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to setup signal monitor");
-            if (signalMonitor)
-            {
-                delete signalMonitor;
-                signalMonitor = NULL;
-            }
-
-            // pretend the signal monitor is running to prevent segfault
-            SetFlags(kFlagSignalMonitorRunning);
-            ClearFlags(kFlagWaitingForSignal);
-            error = true;
-        }
-
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to setup signal monitor");
         if (signalMonitor)
         {
-            if (request.flags & kFlagEITScan)
-            {
-                GetDTVSignalMonitor()->GetStreamData()->
-                    SetVideoStreamsRequired(0);
-                GetDTVSignalMonitor()->IgnoreEncrypted(true);
-            }
-
-            SetFlags(kFlagSignalMonitorRunning);
-            ClearFlags(kFlagWaitingForSignal);
-            if (!antadj)
-                SetFlags(kFlagWaitingForSignal);
+            delete signalMonitor;
+            signalMonitor = NULL;
         }
 
-        if (has_dummy && ringBuffer)
-        {
-            // Make sure recorder doesn't point to bogus ringbuffer before
-            // it is potentially restarted without a new ringbuffer, if
-            // the next channel won't tune and the user exits LiveTV.
-            if (recorder)
-                recorder->SetRingBuffer(NULL);
+        // pretend the signal monitor is running to prevent segfault
+        SetFlags(kFlagSignalMonitorRunning);
+        ClearFlags(kFlagWaitingForSignal);
+        error = true;
+    }
 
-            SetFlags(kFlagDummyRecorderRunning);
-            VERBOSE(VB_RECORD, "DummyDTVRecorder -- started");
-            SetFlags(kFlagRingBufferReady);
-        }
+    if (signalMonitor)
+    {
+        SetFlags(kFlagSignalMonitorRunning);
+        ClearFlags(kFlagWaitingForSignal);
+        if (!antadj)
+            SetFlags(kFlagWaitingForSignal);
+    }
 
-        // if we had problems starting the signal monitor,
-        // we don't want to start the recorder...
-        if (error)
-            return;
+    if (has_dummy && ringBuffer)
+    {
+        // Make sure recorder doesn't point to bogus ringbuffer before
+        // it is potentially restarted without a new ringbuffer, if
+        // the next channel won't tune and the user exits LiveTV.
+        if (recorder)
+            recorder->SetRingBuffer(NULL);
+
+        SetFlags(kFlagDummyRecorderRunning);
+        VERBOSE(VB_RECORD, "DummyDTVRecorder -- started");
+        SetFlags(kFlagRingBufferReady);
     }
 
+    // if we had problems starting the signal monitor,
+    // we don't want to start the recorder...
+    if (error)
+        return;
+
     // Request a recorder, if the command is a recording command
     ClearFlags(kFlagNeedToStartRecorder);
     if (request.flags & kFlagRec && !antadj)
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/tv_rec.h mythtv-0.22.0-fixes23003/libs/libmythtv/tv_rec.h
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/tv_rec.h	2009-10-14 20:32:46.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/tv_rec.h	2009-12-27 02:36:05.000000000 -0600
@@ -161,6 +161,7 @@
 class MPUBLIC TVRec : public SignalMonitorListener
 {
     friend class TuningRequest;
+    friend class SignalMonitor;
 
   public:
     TVRec(int capturecardnum);
@@ -255,6 +256,7 @@
     static TVRec *GetTVRec(uint cardid);
 
     virtual void AllGood(void) { WakeEventLoop(); }
+    virtual void StatusChannelTuned(const SignalMonitorValue&) { }
     virtual void StatusSignalLock(const SignalMonitorValue&) { }
     virtual void StatusSignalStrength(const SignalMonitorValue&) { }
 
@@ -263,6 +265,7 @@
     bool WaitForEventThreadSleep(bool wake = true, ulong time = ULONG_MAX);
     static void *EventThread(void *param);
     static void *RecorderThread(void *param);
+    bool SetupDTVSignalMonitor(bool EITscan);
 
   private:
     void SetRingBuffer(RingBuffer *);
@@ -294,8 +297,8 @@
     FirewireChannel *GetFirewireChannel(void);
     V4LChannel   *GetV4LChannel(void);
 
-    bool SetupSignalMonitor(bool enable_table_monitoring, bool notify);
-    bool SetupDTVSignalMonitor(void);
+    bool SetupSignalMonitor(bool enable_table_monitoring,
+                            bool EITscan, bool notify);
     void TeardownSignalMonitor(void);
     DTVSignalMonitor *GetDTVSignalMonitor(void);
 
@@ -374,6 +377,7 @@
 
     // State variables
     mutable QMutex stateChangeLock;
+    mutable QMutex pendingRecLock;
     TVState        internalState;
     TVState        desiredNextState;
     bool           changeState;
diff -urNad mythtv-0.22.0-fixes23003~/libs/libmythtv/v4lchannel.h mythtv-0.22.0-fixes23003/libs/libmythtv/v4lchannel.h
--- mythtv-0.22.0-fixes23003~/libs/libmythtv/v4lchannel.h	2009-10-14 20:32:51.000000000 -0500
+++ mythtv-0.22.0-fixes23003/libs/libmythtv/v4lchannel.h	2009-12-27 02:37:14.000000000 -0600
@@ -49,7 +49,6 @@
     QString GetSIStandard(void) const { return "atsc"; }
 
     // Commands
-    bool SwitchToInput(int newcapchannel, bool setstarting);
     bool Retune(void);
 
     // Picture attributes.
@@ -69,6 +68,9 @@
     bool Tune(uint frequency, QString inputname,
               QString modulation, QString si_std);
 
+  protected:
+    bool SwitchToInput(int newcapchannel, bool setstarting);
+
   private:
     // Helper Sets
     void SetFreqTable(const int index);
